feat(penpal): live-detect worktree additions and removals#548
Merged
Conversation
Watch each project's .git/worktrees/ directory so that `git worktree add` and `git worktree remove` are detected without restarting the server. On change, full re-discovery runs and an SSE event pushes the updated worktree list to the frontend. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract rediscoverProjects() helper to eliminate duplicated boilerplate across worktree, workspace, and source-detection event handlers - Protect worktreeWatchDirs and gitDirWatches reads in handleEvent with focusMu to prevent concurrent map read/write panic - Watch .git/ directory for projects without existing worktrees so the first `git worktree add` (which creates .git/worktrees/) is detected - Add GitCommonDir() helper extracted from GitWorktreesDir() - Add test for first-worktree creation detection via .git/ watch - Update no-worktrees test to verify .git/ is watched Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove dead code (FindMainWorktree, ResolveWorktree) - Tighten .md-only event filter (drop Create bypass for non-.md files) - Filter .git/ events to only react to worktrees/ creation - Add tests for rediscoverProjects cache update and event filtering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace .git/worktrees/ inotify watches and per-project subprocess calls with zero-cost workspace directory detection. Unexport unused GitCommonDir/GitWorktreesDir, serialize rediscoverProjects, remove redundant .md check, add tests for error paths and Write events. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ktree-dis * origin/main: (45 commits) feat(penpal): persist recent files activity across restarts (#595) feat: persist open windows, tabs, and geometry across app restarts (#588) feat(staged): generate next prefill text when generating notes (#594) feat(staged): add "Run again" button to action output dialog (#593) feat: queue repo sessions in project MCP with async cancellation fix (#591) fix(staged): lowercase "building" subtitle for consistency (#592) fix(staged): use completedAt for commit prefill timeline ranking (#590) fix: add per-branch mutex to prevent worktree setup race condition (#589) feat: add diff commit session launcher (#585) fix: avoid error state for empty titled code reviews (#587) fix: cancel in-flight auto reviews before manual sessions (#584) feat(settings): add repo context search (#583) fix(staged): sort timeline items by completion time so queued items appear before completed ones (#568) fix: drain queued branch sessions from backend lifecycle (#579) fix: restore resume session metadata for resumed actions (#580) feat(staged): add purple diff comment theme (#578) fix(ui): hide branch actions during setup (#572) fix: validate parsed PR URLs before extraction (#577) fix: centralize staged relative time updates (#576) fix: avoid UI freezes when starting background sessions (#575) ... # Conflicts: # apps/penpal/internal/watcher/watcher.go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Previously, Penpal discovered git worktrees once at startup and never refreshed the list. If you ran
git worktree addorgit worktree removewhile Penpal was running, the sidebar's worktree list went stale — showing deleted worktrees and missing new ones.Now, worktree additions and removals are detected automatically via the existing workspace directory watch. When
git worktree add ../foocreates a new sibling directory, the workspace watch fires a rescan that discovers the new worktree. Removal works the same way. No restart needed — the sidebar updates within moments.Design: zero-cost detection
The implementation adds no additional inotify watches, no subprocess calls in the watcher hot path, and no lock acquisitions in the event loop. It piggybacks entirely on the workspace directory watch that was already in place:
git worktree add ../foocreates a new directory in the workspacerediscoverProjectsgit worktree list, updates cache, broadcasts SSEprojectsevent/api/projectsand the sidebar reflects the changeChanges
discovery/worktree.go—gitCommonDirFSresolves the shared.gitdirectory using pure filesystem reads (os.Lstat+os.ReadFile) instead of spawninggit rev-parse. Used by discovery, not by the watcher.watcher/watcher.go— ExtractedrediscoverProjectshelper (serialized withrediscoverMu), tightened.md-only event filter, removed dead code. No worktree-specific watches or event handling.discovery/worktree.go— Removed dead code (FindMainWorktree,ResolveWorktree)🤖 Generated with Claude Code